﻿using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using Fasterflect;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace CY_MVC.Utility
{
    public static class AjaxMethod
    {

        static AjaxMethod()
        {
            Prefix = "p_";
        }

        public static string Prefix
        {
            get;
            set;
        }

        public static readonly Dictionary<string, MethodInvoker> AjaxMethodList = new Dictionary<string, MethodInvoker>();
        public static readonly Dictionary<string, Dictionary<string, ParameterInfo>> AjaxParameterInfoList = new Dictionary<string, Dictionary<string, ParameterInfo>>();
        private static readonly object Locakobj = new object();

        public static string Invoke(object p_Targetobject, string p_Methodname, IDictionary<string, string> p_paramlist)
        {
            string Key = TypeMethodName(p_Targetobject.GetType(), p_Methodname);
            MethodInvoker methodInvoker;
            Dictionary<string, ParameterInfo> parameterinfos;
            lock (Locakobj)
            {
                AjaxMethodList.TryGetValue(Key, out methodInvoker);
                AjaxParameterInfoList.TryGetValue(Key, out parameterinfos);
                if (methodInvoker == null || parameterinfos == null)
                {
                    lock (Locakobj)
                    {
                        var methodinfo = p_Targetobject.GetType().Method(p_Methodname);
                        parameterinfos = methodinfo.GetParameters().ToDictionary(parameterInfo => parameterInfo.Name.ToLowerInvariant());
                        var paramtypes = new List<Type>();
                        foreach (var parameter in parameterinfos)
                        {
                            paramtypes.Add(parameter.Value.ParameterType);
                        }
                        methodInvoker = p_Targetobject.GetType().DelegateForCallMethod(methodinfo.Name, paramtypes.ToArray());

                        AjaxMethodList.Remove(Key);
                        AjaxMethodList.Add(Key, methodInvoker);
                        AjaxParameterInfoList.Remove(Key);
                        AjaxParameterInfoList.Add(Key, parameterinfos);
                    }
                }
            }
            if (methodInvoker != null && parameterinfos != null)
            {
                if (parameterinfos.Count == p_paramlist.Count)
                {
                    var parameters = new List<object>();
                    foreach (var parameter in parameterinfos)
                    {
                        if (TypeHelper.IsSimpleType(parameter.Value.ParameterType))
                        {
                            try
                            {
                                parameters.Add(p_paramlist[parameter.Key.NameNoPrefix()].ConvertSimpleType(parameter.Value.ParameterType));
                            }
                            catch
                            {
                                throw new Exception("简单类型:" + parameter.Value.ParameterType.Name + "转换失败!转换对象:" + p_paramlist[parameter.Key.NameNoPrefix()]);
                            }
                        }
                        else
                        {

                            try
                            {
                                parameters.Add(JsonConvert.DeserializeObject(p_paramlist[parameter.Key.NameNoPrefix()], parameter.Value.ParameterType));
                            }
                            catch
                            {
                                throw new Exception("复杂类型:" + parameter.Value.ParameterType.Name + "转换失败!转换对象:" + p_paramlist[parameter.Key.NameNoPrefix()]);
                            }
                        }
                    }
                    return JsonConvert.SerializeObject(methodInvoker.Invoke(p_Targetobject, parameters.ToArray()));
                }
                return "请求方法" + Key + "的参数个数不对应";
            }
            return "请求方法" + Key + "不存在";
        }

        public static string NameNoPrefix(this string p_ParameterName)
        {
            return p_ParameterName.StartsWith(Prefix)
                       ? p_ParameterName.Remove(0, Prefix.Length)
                       : p_ParameterName;
        }

        public static string TypeMethodName(Type p_Type, MethodInfo p_MethodInfo)
        {
            return TypeMethodName(p_Type, p_MethodInfo.Name);
        }

        public static string TypeMethodName(Type p_Type, string p_MethodName)
        {
            return p_Type.FullName.ToLowerInvariant() + "_" + p_MethodName.ToLowerInvariant();
        }
    }
}
